package com.acme.bankapp.service.bank;

import com.acme.bankapp.domain.bank.Account;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.CheckingAccount;
import com.acme.bankapp.domain.bank.Client;

import java.util.*;

/**
 * @author Gregory Sobko
 */
public class BankReport {

    private class Ordering implements Comparator<Account>{
        private boolean ascending;

        private Ordering(boolean ascending) {
            this.ascending = ascending;
        }

        @Override
        public int compare(Account o1, Account o2) {
            return (ascending ? 1 : -1) * (int)(o1.getBalance() - o2.getBalance());
        }
    }
    /**
     * Sorting orders: ASCENDING and DESCENDING
     */
    public enum AccountSortingOrder {

        ASC(new Ordering(true)),
        DESC(new Ordering(false));

        Comparator<Account> comparator;

        private AccountSortingOrder(Comparator<Account> comparator) {
            this.comparator = comparator;
        }

        public Comparator<Account> getComparator() {
            return comparator;
        }
    }

    private BankReport(){
    }

    /**
     * Returns number of clients in bank
     * @param bank bank
     * @return number of clients
     */
    public static int getNbOfCustomers(Bank bank){
        return bank.getAllClients().size();
    }

    /**
     * @param bank bank
     * @return number of accounts
     */
    public static int getNbOfAccounts(Bank bank){
        return BankService.getAllAccounts(bank).size();
    }

    /**
     * Returns ordered collection
     * @param bank Bank
     * @param order sorting order
     * @return unmodifiable collection
     */
    public Collection<Account> getSorted(Bank bank, AccountSortingOrder order){
        List<Account> list = new ArrayList<Account>(BankService.getAllAccounts(bank));
        Collections.sort(list,order.getComparator());
        return Collections.unmodifiableList(list);
    }

    /**
     * Get total redit of bank
     * @param bank bank
     * @return credit
     */
    public int getBankCredit(Bank bank){
        int sum = 0;
        for(Account account: BankService.getAllAccounts(bank)){
            if(account instanceof CheckingAccount && account.getBalance() < 0 ){
                sum -= account.getBalance();
            }
        }
        return sum;
    }

    /**
     * Returns mapping client &lt;-&gt; accounts
     * @param bank bank
     * @return mapping client to his accounts
     */
    public Map<Client,Collection<Account>> getCustomerAccount(Bank bank){
        Map<Client,Collection<Account>> clientAccounts = new HashMap<>();
        for(Client client: bank.getAllClients()){
            clientAccounts.put(client,client.getAccounts());
        }
        return Collections.unmodifiableMap(clientAccounts);
    }

}
